﻿using System.Linq;
using PloobsEngine.SceneControl;
using PloobsEngine.Physics;
using PloobsEngine;
using PloobsEngine.Cameras;
using PloobsEngine.Input;
using Microsoft.Xna.Framework;
using PloobsEngine.Physics.Bepu;
using PloobsEngine.Modelo;
using PloobsEngine.Material;
using Microsoft.Xna.Framework.Graphics;
using PloobsEngineDemo3;
using PloobsEngine.Features;
using PloobsEngine.Commands;
using PloobsEngine.Loader;
using PloobsEngine.Particle3D;
using System.Collections.Generic;
using PloobsEngine.Light;
using System;
using Microsoft.Xna.Framework.Input;
using Engine.Material.Deferred;
using PloobsEngine.Utils;
using PloobsEngine.DataAquisition;

namespace Etapa1.Screens
{
    public class HDREffectScreen : SceneScreen
    {
        private BepuPhysicWorld physicWorld;
        private BrutalForceWorld mundo;
        private EngineStuff engine;
        ICamera cam;
        List<string> cameranames = new List<string>();
        int actualcam = 0;



        public HDREffectScreen(EngineStuff es)
        {
            this.engine = es;
            physicWorld = new BepuPhysicWorld();
            mundo = new BrutalForceWorld(physicWorld);
            engine.Game.IsFixedTimeStep = false;
        }




        public override void LoadContent(EngineStuff es)
        {
            InputAdvanced inp = new InputAdvanced(engine);
            engine.AddComponent(inp);

            base.LoadContent(es);

            #region LOADER

            ExtractXmlModelLoader me = new ExtractXmlModelLoader();
            ModelLoaderData data = me.Load("ilha");

            foreach (var item in data.ModelMeshesInfo)
            {
                ComposedPartsModel sm = new ComposedPartsModel(item);
                sm.LoadModelo();
                IPhysicObject pi;

                //Só o plano colide o resto não
                if (item.ModelMeshName.Contains("Plane01"))
                {
                    pi = new TriangleMeshObject(sm, item.pos, Matrix.CreateFromQuaternion(item.ori), item.scale);
                }
                else
                {
                    pi = new GhostObject(item.pos, Matrix.CreateFromQuaternion(item.ori), item.scale);
                }

                pi.isMotionLess = true;
                CustomDeferred shader = new CustomDeferred(item.HasTexture(TextureType.GLOW), item.HasTexture(TextureType.BUMP), item.HasTexture(TextureType.SPECULAR), item.HasTexture(TextureType.PARALAX));

                shader.Initialize();
                IMaterial mat = new Material(shader, MaterialType.DEFERRED);
                IObject obj4 = new SimpleObject(mat, pi, sm);
                mundo.AddObject(obj4);
            }

            foreach (var item in data.LightsInfo)
            {
                //mundo.AddLight(item);
            }

            foreach (var item in data.CameraInfo)
            {
                CameraStatic sc = new CameraStatic(item.Position, item.Target);
                sc.Name = item.Name;
                sc.FarPlane = 4000;
                mundo.AddCamera(sc.Name, sc);
                cameranames.Add(item.Name);
            }

            DummyInfo di = data.DummyInfo.First((a) => a.Name == "Fogueira");
            DummyInfo di1 = data.DummyInfo.First((a) => a.Name == "Fumaca");

            #endregion

            cam = new CameraFirstPerson(true);
            cam.FarPlane = 4000;
            cam.Name = "Fp";
            mundo.AddCamera(cam.Name, cam);
            cameranames.Add("Fp");

            mundo.CameraManager.SetActiveCamera(cameranames[0]);

            ////Criacao de uma Tecnica
            DeferredRenderTechnic dr = new DeferredRenderTechnic(engine);

            IRenderTechnic[] rt = new IRenderTechnic[] { dr };
            this.RenderTechnics = rt;
            float amb = 0.1f;
            dr.DeferredFinalCombination.AmbientColor = new Color(amb, amb, amb);
            (dr.DeferredLightMap as LightMap).CullPointLight = false;

            this.RenderTechnics = rt;
            this.World = mundo;

            SkyDome sk = new SkyDome();
            engine.AddComponent(sk);
            SkyDomeParametersCommand su = new SkyDomeParametersCommand(cam, "..\\Content\\Textures\\cloudMap");


            CommandProcessor.getCommandProcessor().SendCommandAssyncronous(su);
            SimpleConcreteKeyboardInputPlayable ikp = new SimpleConcreteKeyboardInputPlayable(StateKey.PRESS, Keys.Space, KeyStateChange, EntityType.CAMERA);
            BindKeyCommand bk = new BindKeyCommand(ikp, BindAction.ADD);
            CommandProcessor.getCommandProcessor().SendCommandAssyncronous(bk);

            string testname = "HDR";
            EngineStuff.DataColector.AddHandler(new GenericNumberColumFileSaver(testname, new string[] { "SMoothFPS", "ObjectNum", "PrimitiveNumberPolyCount", "NumeroLuzes" }, Keys.Enter));
            EngineStuff.DataColector.AddHandler(new FileSaverDataHandler(testname, Keys.Enter));

            SleepTimer st = new SleepTimer(engine, 100, AddGeometry);
            SleepTimer st2 = new SleepTimer(engine, 100, addlight);
            SleepTimer change = new SleepTimer(engine, 6000, nextcam);

            HdrPostEffect p = new HdrPostEffect();
            dr.AddPostEffect(p);

        }

        public void nextcam()
        {
            actualcam++;
            actualcam = actualcam % cameranames.Count;
            mundo.CameraManager.SetActiveCamera(cameranames[actualcam], InterpolationType.BYTIME, 3);
        }
        void KeyStateChange(InputPlayableKeyBoard ipk)
        {

            actualcam++;
            actualcam = actualcam % cameranames.Count;
            mundo.CameraManager.SetActiveCamera(cameranames[actualcam], InterpolationType.BYTIME, 3);

        }
        public void AddGeometry()
        {
            //EngineStuff.DataColector.Recieve(new MethodDataFormat(MethodPart.START,"AddGeometry"));            
            SimpleModel sm = new SimpleModel("..\\Content\\Model\\ton", "..\\Content\\Textures\\ton_diffuse", "..\\Content\\Textures\\ton_normal", "..\\Content\\Textures\\ton_specular");
            sm.LoadModelo();
            IPhysicObject pi = new GhostObject(new Vector3(StaticRandom.RandomBetween(-450, 450), 1, StaticRandom.RandomBetween(-450, 450)), Matrix.Identity, Vector3.One);
            //NormalDeferred shader = new NormalDeferred();
            CustomDeferred shader = new CustomDeferred(false, true, true, false);
            shader.SpecularIntensity = 0.1f;
            shader.SpecularPower = 50;
            shader.Initialize();
            IMaterial mat = new Material(shader, MaterialType.DEFERRED);
            IObject obj3 = new SimpleObject(mat, pi, sm);
            mundo.AddObject(obj3);
            //EngineStuff.DataColector.Recieve(new MethodDataFormat(MethodPart.END, "AddGeometry"));
        }

        public void addlight()
        {
            //EngineStuff.DataColector.Recieve(new MethodDataFormat(MethodPart.START,"AddLight"));            
            PointLight pl = new PointLight(new Vector3(StaticRandom.RandomBetween(-450, 450), 1, StaticRandom.RandomBetween(-450, 450)), StaticRandom.RandomColor(), 50, 2);
            pl.UsePointLightQuadraticAttenuation = true;
            mundo.AddLight(pl);
            //EngineStuff.DataColector.Recieve(new MethodDataFormat(MethodPart.END, "AddLight"));
        }

        public override void Update(GameTime gameTime, bool otherScreenHasFocus, bool coveredByOtherScreen)
        {
            EngineStuff.DataColector.Recieve(new GenericNumberColumDataFormat(gameTime, new double[] { EngineStuff.Clock.SmoothedFPS, mundo.ObjectsNum, mundo.Polycont, mundo.Lights.Count }));
            base.Update(gameTime, otherScreenHasFocus, coveredByOtherScreen);
        }



    }
}

